import sys
import pygame
from pygame.locals import *
from pygame.time import get_ticks
from pygame.event import Event
import widget
from widget import Widget

mod_cmd = KMOD_LCTRL | KMOD_RCTRL | KMOD_LMETA | KMOD_RMETA
double_click_time = 300 # milliseconds

modifiers = dict(
	shift = False,
	ctrl = False,
	alt = False,
	meta = False,
)

modkeys = {
	K_LSHIFT: 'shift',  K_RSHIFT: 'shift',
	K_LCTRL:  'ctrl',   K_RCTRL:  'ctrl',
	K_LALT:   'alt',    K_RALT:   'alt',
	K_LMETA:  'meta',   K_RMETA:  'meta',
}

last_mouse_event = Event(0, pos = (0, 0), local = (0, 0))
last_mouse_event_handler = None

class Cancel(Exception):
	pass

def set_modifier(key, value):
	attr = modkeys.get(key)
	if attr:
		modifiers[attr] = value

def add_modifiers(event):
	d = event.dict
	d.update(modifiers)
	d['cmd'] = event.ctrl or event.meta

class RootWidget(Widget):

	redraw_every_frame = False
	do_draw = False

	def __init__(self, surface):
		Widget.__init__(self, surface.get_rect())
		self.surface = surface
		widget.root_widget = self
	
	def set_timer(self, ms):
		pygame.time.set_timer(USEREVENT, ms)

	def run(self):
		self.run_modal(None)

	def run_modal(self, modal_widget):
		global last_mouse_event, last_mouse_event_handler
		is_modal = modal_widget is not None
		modal_widget = modal_widget or self
		was_modal = modal_widget.is_modal
		modal_widget.is_modal = True
		modal_widget.modal_result = None
		if not modal_widget.focus_switch:
			modal_widget.tab_to_first()
		mouse_widget = None
		clicked_widget = None
		num_clicks = 0
		last_click_time = 0
		self.do_draw = True
		while modal_widget.modal_result is None:
			try:
				if self.do_draw:
					self.draw_all(self.surface)
					self.do_draw = False
					pygame.display.flip()
				events = [pygame.event.wait()]
				events.extend(pygame.event.get())
				for event in events:
					type = event.type
					if type == QUIT:
						self.quit()
					elif type == MOUSEBUTTONDOWN:
						self.do_draw = True
						t = get_ticks()
						if t - last_click_time <= double_click_time:
							num_clicks += 1
						else:
							num_clicks = 1
						last_click_time = t
						event.dict['num_clicks'] = num_clicks
						add_modifiers(event)
						mouse_widget = self.find_widget(event.pos)
						if not mouse_widget.is_inside(modal_widget):
							mouse_widget = modal_widget
						clicked_widget = mouse_widget
						last_mouse_event_handler = mouse_widget
						last_mouse_event = event
						mouse_widget.notify_attention_loss()
						mouse_widget.handle_mouse('mouse_down', event)
					elif type == MOUSEMOTION:
						add_modifiers(event)
						modal_widget.dispatch_key('mouse_delta', event)
						mouse_widget = self.find_widget(event.pos)
						last_mouse_event = event
						if clicked_widget:
							last_mouse_event_handler = mouse_widget
							clicked_widget.handle_mouse('mouse_drag', event)
						else:
							if not mouse_widget.is_inside(modal_widget):
								mouse_widget = modal_widget
							last_mouse_event_handler = mouse_widget
							mouse_widget.handle_mouse('mouse_move', event)
					elif type == MOUSEBUTTONUP:
						add_modifiers(event)
						self.do_draw = True
						mouse_widget = self.find_widget(event.pos)
						if clicked_widget:
							last_mouse_event_handler = clicked_widget
							last_mouse_event = event
							clicked_widget = None
							last_mouse_event_handler.handle_mouse('mouse_up', event)
					elif type == KEYDOWN:
						key = event.key
						set_modifier(key, True)
						self.do_draw = True
						self.send_key(modal_widget, 'key_down', event)
						if last_mouse_event_handler:
							event.dict['pos'] = last_mouse_event.pos
							event.dict['local'] = last_mouse_event.local
							last_mouse_event_handler.setup_cursor(event)
					elif type == KEYUP:
						key = event.key
						set_modifier(key, False)
						self.do_draw = True
						self.send_key(modal_widget, 'key_up', event)
						if last_mouse_event_handler:
							event.dict['pos'] = last_mouse_event.pos
							event.dict['local'] = last_mouse_event.local
							last_mouse_event_handler.setup_cursor(event)
					elif type == USEREVENT:
						if not is_modal:
							self.do_draw = self.redraw_every_frame
							if last_mouse_event_handler:
								event.dict['pos'] = last_mouse_event.pos
								event.dict['local'] = last_mouse_event.local
								add_modifiers(event)
								last_mouse_event_handler.setup_cursor(event)
							self.begin_frame()
			except Cancel:
				pass
		modal_widget.is_modal = was_modal
		#modal_widget.dispatch_attention_loss()
	
	def send_key(self, widget, name, event):
		add_modifiers(event)
		widget.dispatch_key(name, event)
	
	def begin_frame(self):
		pass

	def get_root(self):
		return self

	def has_focus(self):
		return True

	def quit(self):
		if self.confirm_quit():
			sys.exit(0)

	def confirm_quit(self):
		return True

	def get_mouse_for(self, widget):
		last = last_mouse_event
		event = Event(0, last.dict)
		event.dict['local'] = widget.global_to_local(event.pos)
		add_modifiers(event)
		return event
